// DiplomaticMessage.cs
//
// Copyright (c) 2007 Mike Strobel
//
// This source code is subject to the terms of the Microsoft Reciprocal License (Ms-RL).
// For details, see <http://www.opensource.org/licenses/ms-rl.html>.
//
// All other rights reserved.

using System;
using System.ComponentModel;
using System.Linq;

using Supremacy.Entities;
using Supremacy.Game;
using Supremacy.Resources;
using System.Text.RegularExpressions;

namespace Supremacy.Diplomacy
{
    [Serializable]
    public class DiplomaticMessage
    {
        private int _senderId = Civilization.InvalidID;
        private int _recipientId = Civilization.InvalidID;
        private DiplomaticMessageType _messageType;
        private Proposal _proposal;
        private object _parameter;

        private DiplomaticMessage()
        {
            TurnSent = GameContext.Current.TurnNumber;
        }

        public DiplomaticMessage(Civilization sender, Civilization recipient) : this()
        {
            this.Sender = sender;
            this.Recipient = recipient;
        }

        public DiplomaticMessage(Civilization sender, Civilization recipient, DiplomaticMessageType messageType)
            : this(sender, recipient)
        {
            _messageType = messageType;
        }

        public DiplomaticMessage(Civilization sender, Civilization recipient, DiplomaticMessageType messageType, Demeanor demeanor)
            : this(sender, recipient, messageType)
        {
            Demeanor = demeanor;
        }

        #region Properties
        public Civilization Sender
        {
            get { return GameContext.Current.Civilizations[_senderId]; }
            set { _senderId = (value != null) ? value.CivID : Civilization.InvalidID; }
        }

        public Civilization Recipient
        {
            get { return GameContext.Current.Civilizations[_recipientId]; }
            set { _recipientId = (value != null) ? value.CivID : Civilization.InvalidID; }
        }

        public int TurnSent { get; set; }

        public Demeanor Demeanor { get; set; }

        public DiplomaticMessageType MessageType
        {
            get { return _messageType; }
            set { _messageType = value; }
        }

        public string MessageTypeDescription
        {
            get
            {
                if (this.IsWarDeclaration)
                    return "War Declaration";

                if (this.IsThreat)
                    return "Threat";

                if (this.IsStatement)
                    return "Statement";

                if (this.IsCounterProposal)
                    return "Counter-Proposal";

                if (this.IsReply)
                    return "Reply to Proposal";

                if (this.IsGift)
                    return "Gift";

                if (this.IsDemand)
                    return "Demand";

                if (this.HasTreaty)
                    return "Treaty Proposal";

                if (this.IsProposal)
                    return "Proposal";

                if (this.MessageType == DiplomaticMessageType.AgreementTermination)
                    return "Agreement Termination";

                return "Diplomatic Message";
            }
        }

        public Proposal Proposal
        {
            get { return _proposal; }
            set { _proposal = value; }
        }

        public object Parameter
        {
            get
            {
                if (IsProposal)
                {
                    return null;
                }
                if ((IsCommendation || IsDenouncement) && (_parameter != null))
                {
                    TypeConverter converter = TypeDescriptor.GetConverter(typeof(int));
                    if (converter.CanConvertFrom(_parameter.GetType()))
                    {
                        int civId = (int)converter.ConvertFrom(_parameter);
                        if (civId != Civilization.InvalidID)
                        {
                            return GameContext.Current.Civilizations[civId];
                        }
                    }
                    return null;
                }
                return _parameter;
            }
            set
            {
                if (IsProposal)
                {
                    _parameter = null;
                }
                else if (IsCommendation || IsDenouncement)
                {
                    _parameter = (value is Civilization)
                            ? ((Civilization)value).CivID
                            : Civilization.InvalidID;
                }
                else
                {
                    _parameter = value;
                }
            }
        }

        public bool IsReply
        {
            get
            {
                switch(MessageType)
                {
                    case DiplomaticMessageType.ProposalAcceptance:
                    case DiplomaticMessageType.ProposalRejection:
                    case DiplomaticMessageType.CounterProposal:
                        return true;
                }
                return false;
            }
        }

        public bool IsStatement
        {
            get { return (IsCommendation || IsDenouncement || IsThreat); }
        }

        public bool IsDenouncement
        {
            get
            {
                switch (MessageType)
                {
                    case DiplomaticMessageType.DenounceAssault:
                    case DiplomaticMessageType.DenounceInvasion:
                    case DiplomaticMessageType.DenounceRelationship:
                    case DiplomaticMessageType.DenounceSabotage:
                    case DiplomaticMessageType.DenounceWar:
                        return true;
                    default:
                        return false;
                }
            }
        }

        public bool IsCommendation
        {
            get
            {
                switch (MessageType)
                {
                    case DiplomaticMessageType.CommendAssault:
                    case DiplomaticMessageType.CommendInvasion:
                    case DiplomaticMessageType.CommendRelationship:
                    case DiplomaticMessageType.CommendSabotage:
                    case DiplomaticMessageType.CommendWar:
                        return true;
                    default:
                        return false;
                }
            }
        }

        public bool HasTreaty
        {
            get
            {
                if (!IsProposal)
                    return false;
                foreach (Stipulation stipulation in Proposal.OfferStipulations.Union(Proposal.DemandStipulations))
                {
                    if (stipulation is TreatyStipulation)
                        return true;
                }
                return false;
            }
        }

        public bool HasOffers
        {
            get
            {
                if (!IsProposal)
                    return false;
                foreach (Stipulation stipulation in Proposal.OfferStipulations)
                {
                    if (!stipulation.IsMutual)
                        return true;
                }
                return false;
            }
        }

        public bool HasDemands
        {
            get
            {
                if (!IsProposal)
                    return false;
                foreach (Stipulation stipulation in Proposal.DemandStipulations)
                {
                    if (!stipulation.IsMutual)
                        return true;
                }
                return false;
            }
        }

        public bool IsThreat
        {
            get
            {
                switch (MessageType)
                {
                    case DiplomaticMessageType.ThreatAssault:
                    case DiplomaticMessageType.ThreatAggression:
                    case DiplomaticMessageType.ThreatExpansion:
                    case DiplomaticMessageType.ThreatSpying:
                        return true;
                    default:
                        return false;
                }
            }
        }

        public bool IsGift
        {
            get { return ((_messageType == DiplomaticMessageType.Proposal) && (_proposal.IsGift)); }
        }

        public bool IsDemand
        {
            get { return ((_messageType == DiplomaticMessageType.Proposal) && (_proposal.IsDemand)); }
        }

        public bool IsProposal
        {
            get { return ((_messageType == DiplomaticMessageType.Proposal) || IsCounterProposal); }
        }

        public bool IsCounterProposal
        {
            get { return (_messageType == DiplomaticMessageType.CounterProposal); }
        }

        public bool IsWarDeclaration
        {
            get { return (_messageType == DiplomaticMessageType.WarDeclaration); }
        }

        public bool IsValid
        {
            get
            {
                if (IsCommendation || IsDenouncement)
                {
                    return (Parameter is Civilization);
                }
                if ((MessageType == DiplomaticMessageType.Proposal)
                    || (MessageType == DiplomaticMessageType.CounterProposal)
                    || (MessageType == DiplomaticMessageType.ProposalAcceptance)
                    || (MessageType == DiplomaticMessageType.ProposalRejection))
                {
                    return ((Proposal.DemandStipulations.Count > 0) || (Proposal.OfferStipulations.Count > 0));
                }
                return true;
            }
        }

        public CivString MessageText
        {
            get { return GetMessageText(this); }
        }

        public static CivString GetMessageText(DiplomaticMessage message)
        {
            string key = "DIPLOMAT";
            if (message.HasTreaty)
            {
                key += "_TREATY_LEAD_IN";
            }
            else if (message.IsGift)
            {
                key += "_GIFT_LEAD_IN";
            }
            else if (message.IsDemand)
            {
                key += "_DEMAND_LEAD_IN";
            }
            else
            {
                key += Regex.Replace(
                    message.MessageType.ToString(),
                    "([A-Z])",
                    "_$1",
                    RegexOptions.Compiled).ToUpperInvariant();
            }
            return new CivString(message.Sender, CivString.DiplomacyCategory, key, message.Demeanor);
        }
        #endregion

        public static DiplomaticMessage CreateProposal(Civilization sender, Civilization recipient, Demeanor demeanor)
        {
            if (sender == null)
                throw new ArgumentNullException("sender");
            if (recipient == null)
                throw new ArgumentNullException("recipient");
            DiplomaticMessage proposalMessage = new DiplomaticMessage(sender, recipient)
                                                {
                                                    MessageType = DiplomaticMessageType.Proposal,
                                                    Proposal = new Proposal(sender, recipient),
                                                    Demeanor = demeanor
                                                };
            return proposalMessage;
        }

        public static DiplomaticMessage CreateProposalAcceptance(Proposal proposal, Demeanor demeanor)
        {
            if (proposal == null)
                throw new ArgumentNullException("proposal");
            DiplomaticMessage proposalMessage = new DiplomaticMessage(proposal.Recipient, proposal.Sender)
                                                {
                                                    MessageType = DiplomaticMessageType.ProposalAcceptance,
                                                    Proposal = proposal,
                                                    Demeanor = demeanor
                                                };
            return proposalMessage;
        }

        public static DiplomaticMessage CreateProposalRejection(Proposal proposal, Demeanor demeanor)
        {
            if (proposal == null)
                throw new ArgumentNullException("proposal");
            DiplomaticMessage proposalMessage = new DiplomaticMessage(proposal.Recipient, proposal.Sender)
                                                {
                                                    MessageType = DiplomaticMessageType.ProposalRejection,
                                                    Proposal = proposal,
                                                    Demeanor = demeanor
                                                };
            return proposalMessage;
        }

        public static DiplomaticMessage CreateCounterProposal(Proposal originalProposal, Demeanor demeanor)
        {
            if (originalProposal == null)
                throw new ArgumentNullException("originalProposal");
            DiplomaticMessage proposalMessage = new DiplomaticMessage(originalProposal.Recipient, originalProposal.Sender)
                                                {
                                                    MessageType = DiplomaticMessageType.CounterProposal,
                                                    Proposal =
                                                        new Proposal(
                                                        originalProposal.Recipient,
                                                        originalProposal.Sender,
                                                        originalProposal),
                                                    Demeanor = demeanor
                                                };
            return proposalMessage;
        }

        public static DiplomaticMessage CreateAgreementTermination(Civilization sender, Agreement agreement, Demeanor demeanor)
        {
            if (agreement == null)
                throw new ArgumentNullException("agreement");
            DiplomaticMessage message = new DiplomaticMessage(
                sender,
                (sender == agreement.Sender) ? agreement.Recipient : agreement.Sender,
                DiplomaticMessageType.AgreementTermination,
                demeanor)
                                        {
                                            Parameter = agreement
                                        };
            return message;
        }
    }

    public enum DiplomaticMessageType : byte
    {
        CommendWar = 0,
        CommendRelationship,
        CommendAssault,
        CommendInvasion,
        CommendSabotage,
        DenounceWar,
        DenounceRelationship,
        DenounceAssault,
        DenounceInvasion,
        DenounceSabotage,
        ThreatSpying,
        ThreatSabotage,
        ThreatAggression,
        ThreatAssault,
        ThreatExpansion,
        Proposal,
        CounterProposal,
        ProposalAcceptance,
        ProposalRejection,
        AgreementTermination,
        WarDeclaration
    }
}